【Task-07】Angular UI-Router的使用

小课堂【成都第八十八期】

分享人:左少华

目录

1.背景介绍

2.知识剖析

3.常见问题

4.解决方案

5.编码实战

6.扩展思考

7.参考文献

8.更多讨论

1.背景介绍

路由(route),几乎所有的MVC(VM)框架都应该具有的特性,因为它是前端构建单页面应用(SPA)必不可少的组成部分。

对于angular而言,自然也有内置的路由模块-ngRoute。但由于功能的局限性,往往不能满足开发需求。于是,AngularUI团队基于ngRoute开发了第三方模块-UI-Router。

2.知识剖析

UI-Router注入与配置

和ngRoute一样,UI-Router首先需要作为依赖注入应用

                angular.module("myApp", ["ui.router"]).config(function($stateProvider){
        $stateProvider.state(stateName, stateConfig);
                })
            

html标签中设置视图插入位置: 如

                 

UI-router基本参数

$stateProvider:配置应用状态
用法:$stateProvider.state(stateName, stateConfig)

stateConfig:对象,该路由的具体配置项

url:默认相对路径(以^开头的是绝对路径)
views:每个子视图可以包含自己的模板、控制器和预载入数据。设置多视图。如果在单个状态不需要此属性。
template: HTML字符串或者返回HTML字符串的函数(一般用templateUrl)
templateUrl: HTML模板的路径或者返回HTML模板路径的函数
controller、controllerProvider:指定任何已经被注册的控制器或者一个作为控制器的函数
resolve:预载入依赖或数据,注入到控制器中。
onEnter, onExit:路由进入OR退出时执行的函数

1.views:当一个页面需要嵌入多个视图时,可以配置参数,这里介绍相对路径的配置,绝对路径用@的形式,可查看官方文档

                html
  
$stateProvider .state('report',{ views: { 'filters': { templateUrl: 'report-filters.html',//指定模板 controller: function($scope){ ... controller stuff just for filters view ... }//控制器 }, 'tabledata': { templateUrl: 'report-table.html', controller: function($scope){ ... controller stuff just for tabledata view ... } }, 'graph': { templateUrl: 'report-graph.html', controller: function($scope){ ... controller stuff just for graph view ... } } } })

resolve:向该路由控制器注入依赖或数据,格式{string|function}

                resolve: {promiseObj:  function($http){
            return $http({method: 'GET', url: '/someUrl'})
               .then (function (data) {
                   return doSomeStuffFirst(data);
               });
         }},   
                //在controller中注入promiseObj获取值
 controller: function($scope,promiseObj){
          $scope.items = promiseObj.data.items;
          }
                
            

data:注入自定义数据

onEnter 和 onExit 回调函数,在进入该路由和离开该路由时触发

//这个做登陆验证也不错,进入需要登陆的模块时,检测登陆状态,未登陆就跳转,做一些弹窗也可以
                $stateProvider.state("contacts", {
  template: '

{{title}}

', resolve: { title: 'My Contacts' }, controller: function($scope, title){ $scope.title = title; }, onEnter: function(title){ if (title) { ... do something ... } }, onExit: function(title){ if (title) { ... do something ... } } })

3.常见问题

1、路由间参数如何传递?

2、嵌套路由父子关系如何定义?

4.解决方案

1、路由间参数如何传递?

一、通过url传递:url中传递参数也有好几种形式,如(ui-sref="a({}),$state.go('a',({}))")

                url:"/contacts/:contactId" //url中传入参数为 /contacts/42
url: "/contacts/{contactId}"
                //若为查询参数
url: "/contacts?myParam" //将匹配url的“/ contacts?myParam = value”
url: "/contacts?myParam1&myParam2" //will match to url of "/contacts?myParam1=value1&myParam2=wowcool"
            

二、通过params属性设置

                
.state('contacts', {
        url: "/contacts",
        params: {
            param1: null
        },
        templateUrl: 'contacts.html'
    })
View Contacts or $state.go('contacts', {param1: value1})
                
            

2、嵌套路由父子关系如何定义?

                
$stateProvider
    .state('contacts.list', {});//点标记法(推荐)
$stateProvider //parent属性
    .state({
        name: 'list',       // 状态名也可以直接在配置里指定
        parent: 'contacts'  // 父路由的状态名
    });
                
            

5.编码实战

                
 .state('field.moduleDetail', {
                    url: '/moduleEdit?id',
                    templateUrl: 'Pages/moduleEdit.html',
                    controller: 'moduleEditController',
                    controllerAs: 'vm',
                })
ui-sref="field.moduleDetail({id:item.id})" //url 中http://admin.luoboduo.com/#/panel/moduleEdit?id=1
                
                
 .state('field.companyList', { //url:http://admin.luoboduo.com/#/panel/professionMsg (field URL为panel)
                url: '/companyMsg',
                templateUrl: 'Pages/companyMsg.html',
                controller: 'CompanyListController',
                controllerAs: 'vm'

            })
                
            

6.扩展思考

UI-router工作原理?

路由对于前端MVC(VM)而言,就是将hash值(#xxx)与一系列的路由规则进行查找匹配,匹配出一个符合条件的规则,然后根据这个规则,进行数据的获取,以及页面的渲染。

大致过程

1.创建路由规则

.state('home', {
        url: '/abc',
        template: 'hello world'
    });

首先,$urlRouterProvider创建并存储一个state对象,里面包含着该路由规则的所有配置信息。然后,调用$urlRouterProvider.when(...)方法,进行路由的注册(之前是路由的创建)

2.路由查找匹配

(1)angular 在刚开始的$digest时,$rootScope会触发$locationChangeSuccess事件(angular在每次浏览器hash change的时候也会触发$locationChangeSuccess事件)
(2)ui.router 监听了$locationChangeSuccess事件,于是开始通过遍历一系列rules,进行路由查找匹配
(3)当匹配到路由后,就通过$state.transitionTo(state,...),跳转激活对应的state
(4)最后,完成数据请求和模板的渲染

当我们访问http://xxxx#/abc的时候,这个路由规则被匹配到,对应的模板会被填到某个div[ui-view]中

一般路由要对rules进行遍历,但ui-router进行了优化:

ui.router在创建路由时,会实例化一个对应的state对象,并存储起来(states集合里面),每一个state对象都有一个state.name进行唯一标识(如:'home')

当通过ui-sref(会调用$state.go())指令或直接通过$state.go()跳转时,ui-sref="home"指令会给对应的dom添加click事件,然后根据state.name,直接跳转到对应的state,跳转到对应的state之后,ui.router会改变hash,所以触发’$locationChangeSuccess'事件,然后执行回调,在回调中通过一个判断代码规避循环rules

所以尽量避免直接使用href="#/xxx"来改变hash,然后跳转到对应state。这么做将进行rules遍历,浪费性能

7.参考文献

参考一:angular中的路由

参考二:uiroueter官方文档

8.更多讨论

uiRouter中还要很多对应事件,了解之后在项目中很有帮助

state事件
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){ ... })
$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){ ... })
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ ... })
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){ ... })

view事件
View被加载但是DOM树构建之前时:
$scope.$on('$viewContentLoading', function(event, viewConfig){ ... });
View被加载而且DOM树构建完成时:
$scope.$on('$viewContentLoaded', function(event){ ... });

鸣谢

感谢大家观看

BY :李绍博 | 左少华

Contact GitHub API Training Shop Blog About © 2016 GitHub, Inc. Terms Privacy Security Status He